﻿using System.Runtime.CompilerServices;
using RayDen.Library.Core.Primitives;

namespace RayDen.Library.Core
{
    public class HaltonSequence : BaseQMCSequence
    {



        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int rev(int i, int p)
        {
            return i == 0 ? i : p - i;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static float hal(int b, int j)
        {
            int p = primes[b];
            double h = 0.0, f = 1.0 / p, fct = f;
            while (j > 0) { h += rev(j % p, p) * fct; j /= p; fct *= f; }
            return (float)h;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static double hal_d(int b, int j)
        {
            int p = primes[b];
            double h = 0.0, f = 1.0 / p, fct = f;
            while (j > 0) { h += rev(j % p, p) * fct; j /= p; fct *= f; }
            return h;
        }
        public HaltonSequence()
        {
            //this._seed = System.Math.Abs((int)System.DateTime.UtcNow.Ticks >> 16);// (int)System.DateTime.Now.Ticks;
            this._base = (uint)System.Math.Abs((int)System.DateTime.UtcNow.Ticks >> 25);
        }

        public HaltonSequence(int Seed, int Base)
        {
            this._seed = (uint)Seed;
            this._base = (uint)Base;
        }

        public new void Reinitialise(int seed)
        {
            //this._seed = System.Math.Abs(seed >> 16);
            //this._base = System.Math.Abs((int)System.DateTime.UtcNow.Ticks >> 25);

        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override float NextValue(int index)
        {
            if (_base >= primes.Length - 2)
                while (_base >= primes.Length - 2)
                {
                    _base = (uint)System.Math.Abs((int)System.DateTime.UtcNow.Ticks >> 26);
                }

            return hal((int)_base++, index);
        }


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override sealed float NextFloat()
        {

            if (_base >= primes.Length - 2)
                while (_base >= primes.Length - 2)
                {
                    _base = (uint)System.Math.Abs((int)System.DateTime.UtcNow.Ticks >> 26);                
                }

            return hal((int)_base++, (int)_seed++);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override sealed double NextDouble()
        {
            if (_base >= primes.Length - 2)
            {
                _base = 0;
            }

            return hal_d((int)_base, (int)_seed++);
        }
    }

}